package com.jappyframework;

import com.sun.mirror.type.ArrayType;
import com.sun.mirror.type.ClassType;
import com.sun.mirror.type.DeclaredType;
import com.sun.mirror.type.PrimitiveType;
import com.sun.mirror.type.TypeMirror;
import com.sun.mirror.type.VoidType;

/**
 * Some utility methods needed in annotation processing to deal with annotation
 * types.
 * 
 * @author harsh
 */
public class TypeUtils {

	/**
	 * Return if the type is undefined or error type. This happens when we use
	 * an Owl while its been generated.
	 * 
	 * @param type
	 * @return
	 */
	public static boolean isTypeUndefined(TypeMirror type) {
		if (type instanceof ClassType) {
			ClassType ct = (ClassType) type;
			if (ct.getDeclaration() == null) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 
	 * @param type
	 * @return
	 */
	public static boolean isTypePrimitive(TypeMirror type) {
		if (type instanceof PrimitiveType) {
			return true;
		}
		return false;
	}

	/**
	 * 
	 * @param type
	 * @return
	 */
	public static boolean isTypeString(TypeMirror type) {
		if (type instanceof ClassType) {
			ClassType ct = (ClassType) type;

			if (ct.getDeclaration().getQualifiedName().equals(
					"java.lang.String")) {
				return true;
			}
		}
		return false;
	}

	/**
	 * @param type
	 * @return
	 */
	public static boolean isTypePrimitiveOrStringOrVoid(TypeMirror type) {
		if (isTypePrimitive(type))
			return true;
		if (isTypeString(type))
			return true;
		if (isTypeVoid(type)) {
			return true;
		}

		return false;
	}

	public static boolean isPrimitiveEqual(PrimitiveType type, Class<?> c) {
		if (!c.isPrimitive()) {
			return false;
		}
		return c.getName().equalsIgnoreCase(type.getKind().name());
	}

	/**
	 * If the given typemirror is a child of parent class. Arrays need special
	 * care.
	 * 
	 * @param type
	 * @param parent
	 * @return
	 */
	public static boolean isTypeChildOf(TypeMirror type, Class<?> parent) {
		// If array we recurse to the component types.
		if (parent.isArray()) {
			if (!(type instanceof ArrayType)) {
				return false;
			}
			ArrayType at = (ArrayType) type;
			return isTypeChildOf(at.getComponentType(), parent
					.getComponentType());
		}
		if (type instanceof PrimitiveType) {
			return isPrimitiveEqual((PrimitiveType) type, parent);
		}
		if (!(type instanceof DeclaredType)) {
			return false;
		}
		DeclaredType ct = (DeclaredType) type;
		String className = ct.getDeclaration().getQualifiedName();
		System.out.println(className);
		try {
			Class<?> c = Class.forName(className);
			if (!parent.isAssignableFrom(c)) {
				return false;
			}
		} catch (ClassNotFoundException e) {
			return false;
		}
		return true;
	}

	public static boolean isTypeArray(TypeMirror type) {
		return type instanceof ArrayType;
	}

	public static boolean isTypeVoid(TypeMirror type) {
		return (type instanceof VoidType);
	}

}
